package com.chuangsi.project.admin.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chuangsi.common.utils.LocalDateTimeUtils;
import com.chuangsi.common.utils.SecurityUtils;
import com.chuangsi.common.utils.Tool;
import com.chuangsi.framework.aspectj.lang.annotation.DataScope;
import com.chuangsi.project.admin.domain.Order;
import com.chuangsi.project.admin.domain.Plan;
import com.chuangsi.project.admin.domain.Seal;
import com.chuangsi.project.admin.dto.admin.index.*;
import com.chuangsi.project.admin.dto.app.index.*;
import com.chuangsi.project.admin.mapper.OrderMapper;
import com.chuangsi.project.admin.mapper.PlanMapper;
import com.chuangsi.project.admin.service.*;
import com.chuangsi.project.admin.domain.Product;
import com.chuangsi.project.system.mapper.SysDeptMapper;
import com.chuangsi.project.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author ywb
 * @since 2025-02-25
 */
@Service
public class IndexServiceImpl implements IIndexService {

    @Autowired
    private SealService sealService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private IPlanService planService;
    @Autowired
    private ProductService productService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private PlanMapper planMapper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysDeptMapper deptMapper;


    @Override
    public DaySalesAmountDto getDaySalesAmount() {
        //今日数据
        LocalDate now = LocalDate.now();
        LambdaQueryWrapper<Order> todayWrapper = Wrappers.lambdaQuery(Order.class);
        todayWrapper.select(Order::getMoney);
        todayWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        todayWrapper.eq(Order::getAppStatus,2);
        todayWrapper.eq(Order::getDelFlag,0);
        todayWrapper.ge(Order::getCreateTime, now.atTime(LocalTime.MIN));
        todayWrapper.le(Order::getCreateTime, now.atTime(LocalTime.MAX));
        BigDecimal todaytSalesAmount = orderService.list(todayWrapper).stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        //昨日数据
        LocalDate lastDay = LocalDate.now().plusDays(-1);
        LambdaQueryWrapper<Order> lastDayWrapper = Wrappers.lambdaQuery(Order.class);
        lastDayWrapper.select(Order::getMoney);
        lastDayWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        lastDayWrapper.eq(Order::getAppStatus,2);
        lastDayWrapper.eq(Order::getDelFlag,0);
        lastDayWrapper.ge(Order::getCreateTime, lastDay.atTime(LocalTime.MIN));
        lastDayWrapper.le(Order::getCreateTime, lastDay.atTime(LocalTime.MAX));
        BigDecimal lastDaytSalesAmount = orderService.list(lastDayWrapper).stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        String DoD = "100%";
        if(lastDaytSalesAmount.compareTo(BigDecimal.ZERO)>0){
            //计算日环比
            BigDecimal differ = todaytSalesAmount.subtract(lastDaytSalesAmount);
            DoD = differ.divide(lastDaytSalesAmount,2,BigDecimal.ROUND_UP).multiply(BigDecimal.valueOf(100)) +"%";
        }
        return new DaySalesAmountDto(todaytSalesAmount,lastDaytSalesAmount,DoD);
    }

    @Override
    public MonthSalesAmountDto getMonthSalesAmount() {
        //当月数据
        LocalDate now = LocalDate.now();
        LambdaQueryWrapper<Order> monthWrapper = Wrappers.lambdaQuery(Order.class);
        monthWrapper.select(Order::getMoney);
        monthWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        monthWrapper.eq(Order::getAppStatus,2);
        monthWrapper.eq(Order::getDelFlag,0);
        monthWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.firstDayOfMonth(now).atTime(LocalTime.MIN));
        monthWrapper.le(Order::getCreateTime, LocalDateTimeUtils.lastDayOfMonth(now).atTime(LocalTime.MAX));
        BigDecimal monthSalesAmount = orderService.list(monthWrapper).stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        //昨月数据
        LocalDate lastDay = LocalDate.now().plusMonths(-1);
        LambdaQueryWrapper<Order> lastMonthWrapper = Wrappers.lambdaQuery(Order.class);
        lastMonthWrapper.select(Order::getMoney);
        lastMonthWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        lastMonthWrapper.eq(Order::getAppStatus,2);
        lastMonthWrapper.eq(Order::getDelFlag,0);
        lastMonthWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.firstDayOfMonth(lastDay).atTime(LocalTime.MIN));
        lastMonthWrapper.le(Order::getCreateTime, LocalDateTimeUtils.lastDayOfMonth(lastDay).atTime(LocalTime.MAX));
        BigDecimal lastMonthSalesAmount = orderService.list(lastMonthWrapper).stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        String DoD = "100%";
        if(lastMonthSalesAmount.compareTo(BigDecimal.ZERO)>0){
            //计算日环比
            BigDecimal differ = monthSalesAmount.subtract(lastMonthSalesAmount);
            DoD = differ.divide(lastMonthSalesAmount,2,BigDecimal.ROUND_UP).multiply(BigDecimal.valueOf(100)) +"%";
        }
        return new MonthSalesAmountDto(monthSalesAmount,lastMonthSalesAmount,DoD);
    }

    @Override
    public List<MonthSalesProductPieChartDto> getMonthSalesProductPieChart() {
        List<MonthSalesProductPieChartDto> dataList = new ArrayList<>();
        //当月数据
        LocalDate now = LocalDate.now();
        LambdaQueryWrapper<Order> monthWrapper = Wrappers.lambdaQuery(Order.class);
        monthWrapper.select(Order::getMoney,Order::getProductId);
        monthWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        monthWrapper.eq(Order::getAppStatus,2);
        monthWrapper.eq(Order::getDelFlag,0);
        monthWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.firstDayOfMonth(now).atTime(LocalTime.MIN));
        monthWrapper.le(Order::getCreateTime, LocalDateTimeUtils.lastDayOfMonth(now).atTime(LocalTime.MAX));
        List<Order> orderList = orderService.list(monthWrapper);
        List<String> productIdList = orderList.stream().map(Order::getProductId).collect(Collectors.toList());
        if(!productIdList.isEmpty()){
            Map<String,String> productMap = productService.list(Wrappers.lambdaQuery(Product.class)
                    .select(Product::getProductId,Product::getProductName)
                    .in(Product::getProductId,productIdList)
            ).stream().collect(Collectors.toMap(Product::getProductId,Product::getProductName));
            Map<String,List<Order>> orderMap = orderList.stream().collect(Collectors.groupingBy(Order::getProductId));
            orderMap.forEach((productId,orders)->{
                String productName = productMap.getOrDefault(productId,"产品"+productId);
                BigDecimal money = orders.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
                dataList.add(new MonthSalesProductPieChartDto(productName,money));
            });
        }
        return dataList;
    }

    @Override
    public List<MonthSalesSealPieChartDto> getMonthSalesSealPieChart() {
        List<MonthSalesSealPieChartDto> dataList = new ArrayList<>();
        //当月数据
        LocalDate now = LocalDate.now();
        LambdaQueryWrapper<Order> monthWrapper = Wrappers.lambdaQuery(Order.class);
        monthWrapper.select(Order::getMoney,Order::getSealId);
        monthWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        monthWrapper.eq(Order::getAppStatus,2);
        monthWrapper.eq(Order::getDelFlag,0);
        monthWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.firstDayOfMonth(now).atTime(LocalTime.MIN));
        monthWrapper.le(Order::getCreateTime, LocalDateTimeUtils.lastDayOfMonth(now).atTime(LocalTime.MAX));
        List<Order> orderList = orderService.list(monthWrapper);
        List<String> sealIdList = orderList.stream().map(Order::getSealId).collect(Collectors.toList());
        if(!sealIdList.isEmpty()){
            Map<String,String> sealMap = sealService.listByIds(sealIdList).stream().collect(Collectors.toMap(Seal::getSealId,Seal::getSealName));
            Map<String,List<Order>> orderMap = orderList.stream().collect(Collectors.groupingBy(Order::getSealId));
            orderMap.forEach((sealId,orders)->{
                String sealName = sealMap.getOrDefault(sealId,"公司"+sealId);
                BigDecimal money = orders.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
                dataList.add(new MonthSalesSealPieChartDto(sealName,money));
            });
        }
        return dataList;
    }

    @Override
    public TotalSalesDto getTotalSales() {
        LambdaQueryWrapper<Order> wrapper = Wrappers.lambdaQuery(Order.class);
        wrapper.select(Order::getMoney);
        wrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        wrapper.eq(Order::getAppStatus,2);
        wrapper.eq(Order::getDelFlag,0);
        List<Order> orderList = orderService.list(wrapper);
        return new TotalSalesDto(orderList.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add),orderList.size());
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public BigDecimal getTotalSalesAmountForPc(ReqIndexDto req) {
        return orderMapper.getTotalSalesAmountForPc(req);
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public BigDecimal getTotalSalesNumForPc(ReqIndexDto req) {
        return orderMapper.getTotalSalesNumForPc(req);
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<ResDeptRankDto> getDeptSalesRankForPc(ReqIndexDto req) {
        LocalDate today = LocalDate.now();
        req.setStartTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.firstDayOfMonth(today).atTime(LocalTime.MIN)));
        req.setEndTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.lastDayOfMonth(today).atTime(LocalTime.MAX)));
        return orderMapper.getDeptSalesRankForPc(req);
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<MonthSalesAmountLineChartDto> getMonthSalesAmountLineChartForPc(ReqIndexDto req) {
        List<MonthSalesAmountLineChartDto> dataList = new ArrayList<>();
        LocalDate today = LocalDate.now();
        req.setStartTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.getFirstDay(today).atTime(LocalTime.MIN)));
        req.setEndTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.getLastDay(today).atTime(LocalTime.MAX)));
        List<Order> orderList = orderMapper.getOrderListForPc(req);
        for (int month = 1; month < 12; month++) {
            int finalMonth = month;
            List<Order> monthOrderList = orderList.stream().filter(x->x.getCreateTime().getMonthValue() == finalMonth).collect(Collectors.toList());
            dataList.add(new MonthSalesAmountLineChartDto(month+"月",monthOrderList.size(),monthOrderList.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add)));
        }
        return dataList;
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public DaySalesDto getDaySalesForPc(ReqIndexDto req) {
        LocalDate today = LocalDate.now();
        req.setStartTime(LocalDateTimeUtils.formatTime(today.plusDays(-1).atTime(LocalTime.MIN)));
        req.setEndTime(LocalDateTimeUtils.formatTime(today.atTime(LocalTime.MAX)));
        List<Order> orderList = orderMapper.getOrderListForPc(req);
        BigDecimal todayMoney = orderList.stream().filter(x->x.getCreateTime().getDayOfMonth() == today.getDayOfMonth()).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        Integer todayNum      = (int)orderList.stream().filter(x->x.getCreateTime().getDayOfMonth() == today.getDayOfMonth()).count();
        BigDecimal lastDayMoney = orderList.stream().filter(x->x.getCreateTime().getDayOfMonth() == today.plusDays(-1).getDayOfMonth()).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        Integer lastDayNum      = (int)orderList.stream().filter(x->x.getCreateTime().getDayOfMonth() == today.plusDays(-1).getDayOfMonth()).count();
        return new DaySalesDto(todayMoney,todayNum,lastDayMoney,lastDayNum, Tool.dod(todayMoney,lastDayMoney), Tool.dod(BigDecimal.valueOf(todayNum),BigDecimal.valueOf(lastDayNum)));
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public MonthSalesDto getMonthSalesForPc(ReqIndexDto req) {
        LocalDate today = LocalDate.now();
        req.setStartTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.firstDayOfMonth(today.plusMonths(-1)).atTime(LocalTime.MIN)));
        req.setEndTime(LocalDateTimeUtils.formatTime(today.atTime(LocalTime.MAX)));
        List<Order> orderList = orderMapper.getOrderListForPc(req);
        BigDecimal thisMonthMoney = orderList.stream().filter(x->x.getCreateTime().getMonthValue() == today.getMonthValue()).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        Integer thisMonthNum      = (int)orderList.stream().filter(x->x.getCreateTime().getMonthValue() == today.getMonthValue()).count();
        BigDecimal lastMonthMoney = orderList.stream().filter(x->x.getCreateTime().getMonthValue() == today.plusMonths(-1).getMonthValue()).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        Integer lastMonthNum      = (int)orderList.stream().filter(x->x.getCreateTime().getMonthValue() == today.plusMonths(-1).getMonthValue()).count();
        return new MonthSalesDto(thisMonthMoney,thisMonthNum,lastMonthMoney,lastMonthNum, Tool.dod(thisMonthMoney,lastMonthMoney), Tool.dod(BigDecimal.valueOf(thisMonthNum),BigDecimal.valueOf(lastMonthNum)));

    }

    @Override
    public MonthSalesPlanPieChartDto getMonthSalesPlanPieChart() {
        LocalDate now = LocalDate.now();
        Long deptId = SecurityUtils.getDeptId();
        //获取整个部门的计划
        Plan plan = planService.getDeptMonthPlan(deptId,LocalDateTimeUtils.getMonth(now));
        //获取当月订单
        List<Order> orderList = orderService.list(Wrappers.lambdaQuery(Order.class).select(Order::getMoney).eq(Order::getDeptId,deptId).eq(Order::getAppStatus,"2").eq(Order::getDelFlag,0));;
        MonthSalesPlanPieChartDto pieChartDto = new MonthSalesPlanPieChartDto();
        pieChartDto.setMoneyGoal(plan == null?BigDecimal.ZERO:plan.getMoneyGoal());
        pieChartDto.setNumGoal(  plan == null?BigDecimal.ZERO:plan.getNumGoal());
        pieChartDto.setMoneySales(orderList.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add));
        pieChartDto.setNumSales(BigDecimal.valueOf(orderList.size()));
        return pieChartDto;
    }

    @Override
    @DataScope(deptAlias = "d")
    public DeptSalesAchievementRateDto getDeptSalesAchievementRate(ReqIndexDto req) {
        LocalDate today = LocalDate.now();
        req.setStartTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.firstDayOfMonth(today).atTime(LocalTime.MIN)));
        req.setEndTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.lastDayOfMonth(today).atTime(LocalTime.MAX)));
        List<Plan> planList = planMapper.getPlanListForPc(req);
        List<Order> orderList = orderMapper.getOrderListForPc(req);
        //先处理金额达成率
        //金额目标
        BigDecimal moneyGoal  = planList.stream().map(Plan::getMoneyGoal).reduce(BigDecimal.ZERO,BigDecimal::add);
        //销售金额
        BigDecimal moneySales = orderList.stream().map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        //处理数量达成率
        //数量目标
        BigDecimal numGoal  = planList.stream().map(Plan::getNumGoal).reduce(BigDecimal.ZERO,BigDecimal::add);
        //销售数量
        BigDecimal numSales = BigDecimal.valueOf(orderList.size());
        return new DeptSalesAchievementRateDto(moneyGoal,moneySales,numGoal,numSales);
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public BillingRateDto getBillingRate(ReqIndexDto req) {
//        LocalDate today = LocalDate.now();
//        req.setStartTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.firstDayOfMonth(today).atTime(LocalTime.MIN)));
//        req.setEndTime(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.lastDayOfMonth(today).atTime(LocalTime.MAX)));
        //获取销售员数量
        Integer salerNum = userMapper.countUserTypeNum(req);
        //获取开单销售员数量
        Integer billingSalerNum  = orderMapper.getBillingUserNum(req);
        //部门数量
        Integer dealerNum = deptMapper.countDealerNum(req);
        //获取开单部门数量
        Integer billingDealerNum  = orderMapper.getBillingDeptNum(req);
        return new BillingRateDto(salerNum,billingSalerNum,dealerNum,billingDealerNum);
    }


    @Override
    public List<WeekSalesAmountDto> getWeeKSalesAmount() {
        List<String> weekList  = Arrays.asList("星期一","星期二","星期三","星期四","星期五","星期六","星期天");
        List<WeekSalesAmountDto> dataList = new ArrayList<>();
        //今日数据
        LocalDate now = LocalDate.now();

        LambdaQueryWrapper<Order> weekWrapper = Wrappers.lambdaQuery(Order.class);
        weekWrapper.select(Order::getMoney,Order::getCreateTime);
        weekWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        weekWrapper.eq(Order::getAppStatus,2);
        weekWrapper.eq(Order::getDelFlag,0);
        weekWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.getFirstDayOfWeek(now).atTime(LocalTime.MIN));
        weekWrapper.le(Order::getCreateTime,  LocalDateTimeUtils.getLastDayOfWeek(now).atTime(LocalTime.MAX));
        List<Order> thisWeekPayOrderList = orderService.list(weekWrapper);
        //上周数据
        LocalDate lastDay = LocalDate.now().plusWeeks(-1);
        LambdaQueryWrapper<Order> lastWeekWrapper = Wrappers.lambdaQuery(Order.class);
        lastWeekWrapper.select(Order::getMoney,Order::getCreateTime);
        lastWeekWrapper.eq(Order::getUserId,SecurityUtils.getUserId());
        lastWeekWrapper.eq(Order::getAppStatus,2);
        lastWeekWrapper.eq(Order::getDelFlag,0);
        lastWeekWrapper.ge(Order::getCreateTime, LocalDateTimeUtils.getFirstDayOfWeek(lastDay).atTime(LocalTime.MIN));
        lastWeekWrapper.le(Order::getCreateTime, LocalDateTimeUtils.getLastDayOfWeek(lastDay).atTime(LocalTime.MAX));
        List<Order> lastWeekPayOrderList = orderService.list(lastWeekWrapper);
        for (int i = 1; i <= 7; i++) {
            //本周，这天销售数据
            int finalI = i;
            BigDecimal thisWeekDaySalesAmount = thisWeekPayOrderList.stream().filter(x->x.getCreateTime().getDayOfWeek().getValue() == finalI).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal lastWeekDaySalesAmount = lastWeekPayOrderList.stream().filter(x->x.getCreateTime().getDayOfWeek().getValue() == finalI).map(Order::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
            dataList.add(new WeekSalesAmountDto(thisWeekDaySalesAmount,lastWeekDaySalesAmount,weekList.get(i-1)));
        }
        return dataList;
    }



}

























